﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web.UI.WebControls;
using System.Web.UI;
using MethodWorx.CMS.Administration;
using MethodWorx.CMS.Configuration;
using MethodWorx.CMS.Content;
using MethodWorx.CMS.Plugins;
using MethodWorx.CMS.Providers;
using MethodWorx.CMS.TemplateParser;
using MethodWorx.CMS.TemplateParser.Compiler;
using Page = System.Web.UI.Page;

namespace MethodWorx.CMS.Web
{
    public class TemplatePlaceholder : Control
    {
        private static Dictionary<string, Type> compiledPages = new Dictionary<string, Type>();


        public Content.Page CmsPage
        {
            get { return this.CmsRequestContext.Page; }
        }

        public CmsRequestContext CmsRequestContext
        {
            get
            {
                return CmsRequestContext.Current;
            }
        }

        public PageTemplate CmsPageTemplate
        {
            get { return this.CmsPage.Template; }
        }


        protected override void Render(HtmlTextWriter writer)
        {
            var key = this.CmsPageTemplate.Id + "_" + (this.CmsPageTemplate.DatePublished ?? DateTime.Now).Ticks+ "_" + this.PlaceholderName + "_" + this.CmsRequestContext.Preview;
            object instance = null;
            if (compiledPages.ContainsKey(key))
            {
                var type = compiledPages[key];
                var engine = GetParsingEngine();
                instance = TemplateCompiler.CreateTemplateInstance(type, engine, CmsRequestContext.Current, (t) => WebConfiguration.Instance.GetService(t));
            }
            else
            {
                Type type = null;
                var engine = GetParsingEngine();
                if(this.CmsRequestContext.Preview)
                {
                    instance = engine.GetCompiler().Compile(Web.CmsRequestContext.Current, (ty) => WebConfiguration.Instance.GetService(ty));
                }
                else
                {
                    var compiler = new TemplateCompiler(engine);
                    if (this.CmsPage.PublishedPlaceholders.ContainsKey(this.PlaceholderName.ToLower()))
                        type = compiler.Compile(this.CmsPage.PublishedPlaceholders[this.PlaceholderName.ToLower()]);
                }

                if (type != null)
                {
                    compiledPages.Add(key, type);
                    instance = TemplateCompiler.CreateTemplateInstance(type, engine, CmsRequestContext.Current,
                                                               (t) => WebConfiguration.Instance.GetService(t));
                }

            }

            if (instance != null)
            {
                var output = instance.GetType().InvokeMember("Execute",
                                                             BindingFlags.InvokeMethod | BindingFlags.Public |
                                                             BindingFlags.Instance,
                                                             null, instance, null);
                writer.Write(output);
            }
            base.Render(writer);
        }

        private ParsingEngine GetParsingEngine()
        {
            var service =
           new PluginService(
               WebConfiguration.Instance.Provider.GetUnitOfWorkFactory(),
               WebConfiguration.Instance.Provider.GetService<IPluginUserDataRepository>(),
               WebConfiguration.Instance.Provider.GetService<IPluginRepository>());

            var applicationSettings =
                WebConfiguration.Instance.Provider.GetService<IApplicationSettingsRepository>();

            var plugins = new PluginRepository(
                WebConfiguration.Instance.Provider,
                WebConfiguration.Instance.Provider.GetUnitOfWorkFactory(),
                WebConfiguration.Instance.Provider.GetRepositoryRegistry());

            return new ParsingEngine(WebConfiguration.Instance.Provider, this.CmsRequestContext.Page.Template,
                                                  new PluginFactory(applicationSettings, plugins), null, this.PlaceholderName);
        }

        public string PlaceholderName { get; set; }

    }
}
